//
//  MoyaProvider+Cache.swift
//  Lease_IOS
//
//  Created by Mr.wang on 2018/12/20.
//  Copyright © 2018 Mr.wang. All rights reserved.
//

import Moya
import RxSwift

let cacheStatusCode = 199

extension MoyaProviderType {
    
    @discardableResult
    public func loadCache(_ target: Target, completion: @escaping Completion) -> Cancellable {
        
        let cacheDirectoryPath = NSHomeDirectory() + "/Library/Caches/com.moya.cache/"
        if !FileManager.default.fileExists(atPath: cacheDirectoryPath) {
            try? FileManager.default.createDirectory(atPath: cacheDirectoryPath, withIntermediateDirectories: true, attributes: nil)
        }
        
        let key = target.path
        let cacheKey = key.md5()
        let filePath = cacheDirectoryPath + cacheKey
        
        if FileManager.default.fileExists(atPath: filePath),
            let data = try? Data.init(contentsOf: URL.init(fileURLWithPath: filePath), options: Data.ReadingOptions.mappedIfSafe) {
            let response = Response(statusCode: cacheStatusCode, data: data)
            completion(Result.success(response))
        }
        
        let cancellableToken = self.request(target, callbackQueue: nil, progress: nil) { (result) in
            switch result {
            case let .success(response):
                if response.decode().isSuccess {
                    try? response.data.write(to: URL.init(fileURLWithPath: filePath), options: Data.WritingOptions.atomic)
                }
                completion(Result.success(response))
                break
            case let .failure(error):
                completion(Result.failure(error))
                break
            }
        }
        return cancellableToken
    }
    
}

public extension Reactive where Base: MoyaProviderType {
    
    func loadCache(_ target: Base.Target) -> Observable<Moya.Response> {
        return Observable.create { [weak base] observer in
            let cancellableToken = base?.loadCache(target, completion: { (result) in
                switch result {
                case let .success(response):
                    observer.onNext(response)
                    if response.statusCode != cacheStatusCode {
                        observer.onCompleted()
                    }
                case let .failure(error):
                    observer.onError(error)
                }
            })
            return Disposables.create {
                cancellableToken?.cancel()
            }
        }
    }
    
}
